#ifndef __M_REGISTRY_H__
#define __M_REGISTRY_H__

#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <etcd/Watcher.hpp>
#include <etcd/Value.hpp>
#include <thread>
#include <functional>
#include <iostream>
#include "../_spdlog/logger.hpp"

namespace zhong
{
    // 对etcd的二次封装
    namespace etcder
    {
        class Registry
        {
        public:
            using ptr = std::shared_ptr<Registry>;
            Registry(const std::string &local_host)
                : _client(std::make_shared<etcd::Client>(local_host)),
                  _keep_alive(_client->leasekeepalive(3).get()),
                  _lease_id(_keep_alive->Lease()) {}
            ~Registry()
            {
                _keep_alive->Cancel();
            }
            bool registry(const std::string &service_name, const std::string &dest_host)
            {
                auto response = _client->put(service_name, dest_host).get();
                if (response.is_ok() == false)
                {
                    LOG_ERROR("新增键值对[{}-{}]失败, 原因[{}]", service_name, dest_host, response.error_message());
                    return false;
                }
                return true;
            }

        private:
            std::shared_ptr<etcd::Client> _client;
            std::shared_ptr<etcd::KeepAlive> _keep_alive;
            uint64_t _lease_id;
        };
        class Discovery
        {
        public:
            using ptr = std::shared_ptr<Discovery>;
            using NotifyCallback = std::function<void(std::string, std::string)>;
            Discovery(const std::string &service_dir,
                      const std::string &dest_host,
                      const NotifyCallback &put_cb,
                      const NotifyCallback &del_cb)
                : _client(std::make_shared<etcd::Client>(dest_host)),
                  _put_callback(put_cb),
                  _del_callback(del_cb)
            {
                // 进行服务发现
                auto response = _client->ls(service_dir).get();
                if (response.is_ok() == false)
                {
                    LOG_ERROR("获取服务数据失败, 原因[{}]", response.error_message());
                    return;
                }
                int size = response.keys().size();
                for (int i = 0; i < size; i++)
                {
                    std::cout << __FILE__ << ":" << __LINE__ << "提供服务内容如下：" << std::endl;
                    std::cout << "主机[" << response.value(i).as_string() << "]提供服务[" << response.key(i) << "]" << std::endl;
                    if (_put_callback != nullptr)
                    {
                        _put_callback(response.key(i), response.value(i).as_string());
                    }
                    _watcher = std::make_shared<etcd::Watcher>(_client.get(), service_dir,
                                                               std::bind(&Discovery::callback, this, std::placeholders::_1), true);
                }
            }

        private:
            void callback(const etcd::Response &response)
            {
                if (response.is_ok() == false)
                {
                    LOG_ERROR("收到错误事件, 原因[{}]", response.error_message());
                    return;
                }

                // .events() 返回存储事件的vector
                for (auto event : response.events())
                {
                    // 获取事件类型
                    auto type = event.event_type();

                    if (type == etcd::Event::EventType::PUT)
                    {
                        if (_put_callback != nullptr)
                        {
                            _put_callback(event.kv().key(), event.kv().as_string());
                        }
                        LOG_INFO("服务[{}-{}]新增", event.kv().key(), event.kv().as_string());
                    }
                    else if (type == etcd::Event::EventType::DELETE_)
                    {
                        if (_del_callback != nullptr)
                        {
                            _del_callback(event.prev_kv().key(), event.prev_kv().as_string());
                        }
                        LOG_INFO("服务[{}-{}]下线", event.prev_kv().key(), event.prev_kv().as_string());
                    }
                }
            }

        private:
            NotifyCallback _put_callback;
            NotifyCallback _del_callback;
            std::shared_ptr<etcd::Client> _client;
            std::shared_ptr<etcd::Watcher> _watcher;
        };
    }
}

#endif